現如今開發流程中少不了測試驗證程式的正確性,但由於工程師身為一個懶人代表,不可能天天在那邊手動觸發測試,於是乎開始有了 CI (持續整合),簡單來說就是當我們 code commit 後會自動觸發的一整套流程。
那部署呢?大家可以想想如果今天上版頻率不低的情況下,如果部署不做自動化,那每次上版帶來的時間成本累積起來是非常可觀的一件事,所以這時候我們需要 CD (持續部署),來快速交付新功能。
那 Ansible 可以為 CI/CD 流程中帶來什麼樣的變化呢?前幾天有提到的,Ansible 可以幫助我們做到環境一致性,統一的部署流程,具有冪等性。
安裝 Ansible 插件:
# 在 Jenkins 中安裝 Ansible Plugin
# 管理 Jenkins → 管理插件 → 可用插件 → 搜尋 "Ansible"
配置 Ansible 工具:
# 全域工具配置 → Ansible installations
# Name: ansible
# Path to ansible executables directory: /usr/local/bin/
筆者非常推薦如果是使用 Jenkins 的各位,請盡量使用 Jenkinsfile,搭配 groovy language 非常好用,大推
pipeline {
// 如果各位有多台 instance 可以在這邊指定,或者運行在 docker 上都可以
agent any
// 定義環境變數
environment {
ANSIBLE_HOST_KEY_CHECKING = 'False'
ANSIBLE_FORCE_COLOR = 'true'
}
// 設定 input 參數
parameters {
choice(
name: 'ENVIRONMENT',
choices: ['dev', 'staging', 'prod'],
description: '選擇部署環境'
)
string(
name: 'VERSION',
defaultValue: 'latest',
description: '應用程式版本'
)
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: '<https://github.com/your-org/ansible-playbooks.git>'
}
}
stage('Lint Check') {
steps {
sh '''
ansible-lint playbooks/
yamllint .
'''
}
}
stage('Syntax Check') {
steps {
ansiblePlaybook(
playbook: 'playbooks/site.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini",
extras: '--syntax-check'
)
}
}
stage('Deploy') {
steps {
ansiblePlaybook(
playbook: 'playbooks/site.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini",
extras: "--extra-vars 'app_version=${params.VERSION}'",
credentialsId: 'ansible-vault-password'
)
}
}
stage('Verify Deployment') {
steps {
ansiblePlaybook(
playbook: 'playbooks/verify.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini"
)
}
}
stage('Notify') {
steps {
script {
if (currentBuild.result == 'SUCCESS') {
slackSend(
color: 'good',
message: "✅ 部署成功: ${env.JOB_NAME} - ${params.ENVIRONMENT} - ${params.VERSION}"
)
} else {
slackSend(
color: 'danger',
message: "❌ 部署失敗: ${env.JOB_NAME} - ${params.ENVIRONMENT}"
)
}
}
}
}
}
post {
always {
cleanWs()
}
failure {
emailext(
subject: "部署失敗: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "部署到 ${params.ENVIRONMENT} 環境失敗,請檢查 Jenkins 日誌。",
to: "devops@company.com"
)
}
}
}
# 將剛剛寫好的 Jenkinsfile 放到 Github 上面放,進行版本控制
# 建置觸發器,每五分鐘會去 Github 檢查
- GitHub hook trigger for GITScm polling
- Poll SCM: H/5 * * * * # 每5分鐘檢查一次
# 部署方式很多種就看個人喜好去做設定,另外也可以透過 Github 進行版本控制,但手動在 Jenkins 上做觸發的動作
Jenkins Pipeline 藍綠部署:
stage('Blue-Green Deployment') {
steps {
script {
// 部署到 Green 環境
ansiblePlaybook(
playbook: 'playbooks/blue-green-deploy.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini",
extras: "--extra-vars 'target_color=green app_version=${params.VERSION}'"
)
// 健康檢查
def healthCheck = ansiblePlaybook(
playbook: 'playbooks/health-check.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini",
extras: "--extra-vars 'target_color=green'"
)
if (healthCheck.result == 'SUCCESS') {
// 切換流量到 Green
ansiblePlaybook(
playbook: 'playbooks/switch-traffic.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini",
extras: "--extra-vars 'active_color=green'"
)
// 停止 Blue 環境
ansiblePlaybook(
playbook: 'playbooks/cleanup-blue.yml',
inventory: "inventories/${params.ENVIRONMENT}/inventory.ini"
)
} else {
error("Health check failed, aborting deployment")
}
}
}
}
問題現象:
Permission denied (publickey)
解決方案:
ssh-agent
管理多個金鑰ansible_user
權限是否足夠問題現象:
ERROR! Attempting to decrypt but no vault secrets found
解決方案:
-vault-password-file
路徑是否正確問題現象:
Pipeline 執行時間過長或無響應
解決方案:
async
和 poll
處理長時間任務問題現象:
不同環境的部署結果不一致
解決方案:
明天來聊聊監控